#pragma once
#include "mypthread.h"
#include <queue>
#include <vector>
#include <pthread.h>

template <class T>
class threadpool
{
private:
    void Lock()
    {
        pthread_mutex_lock(&_mutex);
    }
    void unLock()
    {
        pthread_mutex_unlock(&_mutex);
    }
    threadpool(int num)
        : _threadnum(num), _wait_num(0)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < num; i++)
        {
            std::string name = "thread---" + std::to_string(i);
            _thread.emplace_back(std::bind(&threadpool::HanderTask, this, name));
        }
    }
    threadpool(threadpool<T> &x) = delete;
    threadpool<T> &operator=(threadpool<T> &x) = delete;

public:
    static threadpool<T> *GetInstance(int num = 5)
    {
        if (_instance == nullptr)
        {
            pthread_mutex_lock(&_instance_mutex);
            if (_instance == nullptr)
            {
                _instance = new threadpool<T>(5);
                _instance->start();
                return _instance;
            }
            pthread_mutex_unlock(&_instance_mutex);
        }
        return _instance;
    }
    void HanderTask(std::string name)
    {
        while (true)
        {
            Lock();
            while (_task_queue.empty())
            {
                _wait_num++;
                pthread_cond_wait(&_cond, &_mutex);
                _wait_num--;
            }
            T t = _task_queue.front();
            _task_queue.pop();
            unLock();

            std::cout << name << std::endl;
            t();
            std::cout << "-------------------" << std::endl;
        }
    }
    void push(const T &task)
    {
        Lock();
        _task_queue.push(task);
        if (_wait_num > 0)
            pthread_cond_signal(&_cond);
        unLock();
    }
    void start()
    {
        for (auto &e : _thread)
            e.Start();
    }
    void wait()
    {
        for (auto &e : _thread)
            e.Join();
    }
    ~threadpool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    int _threadnum;
    std::queue<T> _task_queue;
    std::vector<Thread> _thread;
    int _wait_num;

    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static threadpool<T> *_instance;
    static pthread_mutex_t _instance_mutex;
};

template <class T>
threadpool<T> *threadpool<T>::_instance = nullptr;

template <class T>
pthread_mutex_t threadpool<T>::_instance_mutex = PTHREAD_MUTEX_INITIALIZER;